home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 090 / cit.arc / MSG.C < prev    next >
C/C++ Source or Header  |  1986-01-12  |  47KB  |  1,552 lines

  1. /************************************************************************/
  2. /*                msg.c                    */
  3. /*                                    */
  4. /*    Message handling for Citadel bulletin board system        */
  5. /************************************************************************/
  6.  
  7. /************************************************************************/
  8. /*                history                 */
  9. /*                                    */
  10. /* 86Jan12 HAW    deleteMessage and moveMessage split from pullIt.    */
  11. /* 86Jan04 HAW    Null-named rooms no longer mess up Aide room/msg del.    */
  12. /* 85Nov11 HAW    Rewrite yesterday's mistake.                */
  13. /* 85Nov10 HAW    Fix Held net messages, problem with reverse deletions.    */
  14. /* 85Sep21 HAW    Fix bugs of 85Sep15.                    */
  15. /* 85Sep15 HAW    Update for adding tag indicating a message is outgoing. */
  16. /* 85Aug27 HAW    Move putNetMessage into this file from MISC.C.        */
  17. /* 85Aug24 HAW    Install code for having two msg disks, 1 RAM, 1 disk.    */
  18. /* 85Aug20 HAW    Install code for System Announcement.            */
  19. /* 85Aug17 HAW    Update to onLine() and gotCarrier().            */
  20. /* 85Aug08 HAW    Fix mAbort() to detect 'silent' carrier loss.        */
  21. /* 85Jul05 HAW    Cull out ^Ls from messages.                */
  22. /* 85Jul04 HAW    Insert code to handle "moving" messages.        */
  23. /* 85Jun03 HAW    Tweak code for networking stuff             */
  24. /* 85May16 HAW  Install <H>eld message option                           */
  25. /* 85May13 HAW  Now last message read by caller is printed on <N>ew     */
  26. /* 85Mar20 HAW    Time stamp messages for the nosy types.         */
  27. /* 85Mar13 HAW    Move zapMsgFile() to confg.c                */
  28. /* 85Mar10 HAW    Stop printing messages when lose carrier.        */
  29. /* 85Mar06 HAW    Change mPrintf() to use mFormat().            */
  30. /* 85Feb22 HAW    Implement upload/download.                */
  31. /* 85Feb20 HAW    Implement IMPERVIOUS flag.                */
  32. /* 85Jan19 HAW    Move findPerson() from here to LOG.C.            */
  33. /* 84Sep19 HAW    Can NOT send mail to oneself.                */
  34. /* 84Sep16 JLS    Now recipient's name is recorded like Citadel thinks.    */
  35. /* 84Sep15 HAW    Modified for "POLICY.HLP" masses file.            */
  36. /* 84Sep01 HAW    Msg # no longer split. Note networking problem.     */
  37. /* 84Aug30 HAW    Start upgrade to MS-DOS.                */
  38. /* 84Jul03 HAW    mPrintf, dPrintf, and mWCprintf upgraded to BDS 1.50a.    */
  39. /* 84Jun23 HAW & JLS  Unused local variables zapped.            */
  40. /* 84Jun07 HAW    Responses in Mail now automatically get recipient.    */
  41. /* 84May07 JLS & HAW Implemented the configuration switch ENTEROK.    */
  42. /* 84Mar29 HAW Start upgrade to BDS C 1.50a, identify _spr problem.    */
  43. /* 83Mar03 CrT & SB   Various bug fixes...                */
  44. /* 83Feb27 CrT    Save private mail for sender as well as recipient.    */
  45. /* 83Feb23    Various.  transmitFile() won't drop first char on WC... */
  46. /* 82Dec06 CrT    2.00 release.                        */
  47. /* 82Nov05 CrT    Stream retrieval.  Handles messages longer than MAXTEXT.*/
  48. /* 82Nov04 CrT    Revised disk format implemented.            */
  49. /* 82Nov03 CrT    Individual history begun.  General cleanup.        */
  50. /************************************************************************/
  51.  
  52. #include "ctdl.h"
  53.  
  54. #define TEST_SYS
  55.  
  56. /************************************************************************/
  57. /*                contents                */
  58. /*                                    */
  59. /*    aideMessage()        saves auto message in Aide>        */
  60. /*    dGetWord()        reads a word off disk            */
  61. /*    doActualWrite()     to allow two message files for bkp    */
  62. /*    doFlush()        writes out to specified msg file    */
  63. /*  #    dPree()         special utility for dPrintf & mWCprintf */
  64. /*  #    dPrintf()        printf() that writes to disk        */
  65. /*    fakeFullCase()        converts uppercase message to mixed case*/
  66. /*    flushMsgBuf()        wraps up message-to-disk store        */
  67. /*    getMessage()        load message into RAM            */
  68. /*    getMsgChar()        returns successive chars off disk    */
  69. /*    getMsgStr()        reads a string out of message.buf    */
  70. /*    getWord()        gets one word from message buffer    */
  71. /*    mAbort()        checks for user abort of typeout    */
  72. /*    makeMessage()        menu-level message-entry routine    */
  73. /*    mFormat()        formats a string to modem and console    */
  74. /*    mPeek()         sysop debugging tool--shows ctdlmsg.sys */
  75. /*  #    mPrintf()        writes a line to modem & console    */
  76. /*  #    mWCprintf()        special mPrintf for WC transfers    */
  77. /*    noteLogMessage()    enter message into log record        */
  78. /*    noteMessage()        enter message into current room     */
  79. /*    note2Message()        noteMessage() local            */
  80. /*    printMessage()        prints a message on modem & console    */
  81. /*    pullIt()        sysop special message-removal routine    */
  82. /*    putLong()        puts a long integer to file        */
  83. /*    putMessage()        write message to disk            */
  84. /*    putMsgChar()        writes successive message chars to disk */
  85. /*    putNetMessage()     write net message to disk        */
  86. /*    putWord()        writes one word to modem & console    */
  87. /*    showMessages()        menu-level show-roomful-of-messages fn    */
  88. /*    startAt()        setup to read a message off disk    */
  89. /*    unGetMsgChar()        return a char to getMsgChar()        */
  90. /*                                    */
  91. /*    # -- functions that will give problems when porting        */
  92. /************************************************************************/
  93.  
  94. /************************************************************************/
  95. /*           External variable declarations in MSG.C        */
  96. /************************************************************************/
  97. static unsigned char GMCCache;    /* To unGetMsgChar() into        */
  98. struct msgB         msgBuf;    /* The -sole- message buffer        */
  99. struct msgB         tempMess;    /* For held messages            */
  100. FILE             *msgfl;    /* file descriptor for the msg file    */
  101. FILE             *msgfl2;    /* disk based backup msg file        */
  102. unsigned char         crtColumn; /* current position on screen        */
  103. char             outFlag = OUTOK;    /* will be one of the above    */
  104. char             pullMessage = FALSE;/* true to pull current message*/
  105. unsigned         pulledMLoc;/* loc of pulled message        */
  106. ulong             pulledMId = 0l;    /* id of message to be pulled    */
  107. char             heldMessage;
  108. label             oldTarget;
  109.  
  110. #ifdef _C86_BIG     /*Black magic stuff */
  111. static int         j;
  112. static unsigned char **starr[5];
  113. #endif
  114.  
  115. struct mBuf {
  116.     unsigned char sectBuf[SECTSIZE];
  117.     int       thisChar;
  118.     unsigned      thisSector;
  119.     int       oldChar;
  120.     unsigned      oldSector;
  121. } ;
  122.  
  123. static struct mBuf mFile1, mFile2;
  124.  
  125. /************************************************************************/
  126. /*           External variable definitions for MSG.C        */
  127. /************************************************************************/
  128. extern struct config    cfg;        /* Configuration variables    */
  129. extern struct lTable    *logTab;    /* The people            */
  130. extern struct logBuffer logBuf;     /* Buffer for the pippuls    */
  131. extern struct aRoom    roomBuf;    /* Room buffer            */
  132. extern struct rTable    roomTab[MAXROOMS];
  133. extern struct netTable    *netTab;
  134. extern struct netBuffer netBuf;
  135. extern int        thisRoom;    /* Current room         */
  136. extern int        thisNet;    /* Current node in use        */
  137. extern int        thisLog;    /* Current log position     */
  138. extern char        echo;        /* Output flag            */
  139. extern char        echoChar;
  140. extern char        loggedIn;    /* Logged in flag        */
  141. extern char        aide;        /* aide?            */
  142. extern char        sendTime;    /* User wants to know time    */
  143. extern char        whichIO;    /* Who gets output?        */
  144. extern unsigned char    termWidth;    /* How big's the terminal?    */
  145. extern char        prevChar;    /* Output's evil purposes    */
  146. extern char        expert;     /* Expert?            */
  147. extern char        usingWCprotocol;/* Flag             */
  148. extern char        haveCarrier;    /* Flag             */
  149. extern char        onConsole;    /* Flag             */
  150. extern char        oldToo;     /* Print old msg on New request?*/
  151. extern int        exitValue;
  152. extern char        debug;
  153.  
  154. /************************************************************************/
  155. /*           External function definitions for MSG.C        */
  156. /************************************************************************/
  157. char          BBSCharReady();
  158. char          iChar();
  159. char          toUpper();
  160. char          putMessage();
  161. unsigned char getMsgChar();
  162.  
  163. /************************************************************************/
  164. /*    aideMessage() saves auto message in Aide>            */
  165. /************************************************************************/
  166. aideMessage(noteDeletedMessage)
  167. char noteDeletedMessage;
  168. {
  169.     int ourRoom;
  170.  
  171.     /* message is already set up in msgBuf.mbtext */
  172.     putRoom(ourRoom = thisRoom);
  173.     getRoom(AIDEROOM);
  174.  
  175.     strCpy(msgBuf.mbauth, "Citadel");
  176.     msgBuf.mbto[0] = '\0';
  177.     if (putMessage( /* uploading== */ FALSE))    noteMessage(NULL, ERROR);
  178.  
  179.     if (noteDeletedMessage)   {
  180.     note2Message(pulledMId, pulledMLoc);
  181.     }
  182.  
  183.     putRoom(AIDEROOM);
  184.     noteRoom();
  185.     getRoom(ourRoom);
  186. }
  187.  
  188. /************************************************************************/
  189. /*    deleteMessage() deletes message for pullIt()            */
  190. /************************************************************************/
  191. deleteMessage(m)
  192. int m;
  193. {
  194.     int i;
  195.  
  196.     /* record vital statistics for possible insertion elsewhere: */
  197.     mPrintf("elete message\n ");
  198.     pulledMLoc = roomBuf.msg[m].rbmsgLoc;
  199.     pulledMId  = roomBuf.msg[m].rbmsgNo ;
  200.  
  201.     if (thisRoom == AIDEROOM)    return TRUE;
  202.  
  203.     /* return emptied slot: */
  204.     for (i = m;  i > 0;  i--) {
  205.     roomBuf.msg[i].rbmsgLoc      = roomBuf.msg[i - 1].rbmsgLoc;
  206.     roomBuf.msg[i].rbmsgNo         = roomBuf.msg[i - 1].rbmsgNo ;
  207.     }
  208.     roomBuf.msg[0].rbmsgNo   = 0l;    /* mark new slot at end as free */
  209.     roomBuf.msg[0].rbmsgLoc  = 0;      /* mark new slot at end as free */
  210.  
  211.     /* store revised room to disk before we forget...    */
  212.     noteRoom();
  213.     putRoom(thisRoom);
  214.  
  215.     /* note in Aide>: */
  216.     sPrintf(msgBuf.mbtext, "Following message from %s deleted by %s:",
  217.    (msgBuf.mbauth[0]) ? msgBuf.mbauth : "<anonymous>", logBuf.lbname);
  218.     aideMessage( /* noteDeletedMessage== */ TRUE);
  219.     return TRUE;
  220. }
  221.  
  222. /************************************************************************/
  223. /*    dGetWord() fetches one word from current message, off disk    */
  224. /*    returns TRUE if more words follow, else FALSE            */
  225. /************************************************************************/
  226. char dGetWord(dest, lim)
  227. char *dest;
  228. int  lim;
  229. {
  230.     char c;
  231.  
  232.     --lim;    /* play it safe */
  233.  
  234.     /* pick up any leading blanks: */
  235.     for (c = getMsgChar();   c == ' '  &&  c && lim;   c = getMsgChar()) {
  236.     if (lim) { *dest++ = c;   lim--; }
  237.     }
  238.  
  239.     /* step through word: */
  240.     for (         ;  c != ' ' && c && lim;   c = getMsgChar()) {
  241.     if (lim) { *dest++ = c;   lim--; }
  242.     }
  243.  
  244.     /* trailing blanks: */
  245.     for (         ;   c == ' ' && c && lim;   c = getMsgChar()) {
  246.     if (lim) { *dest++ = c;   lim--; }
  247.     }
  248.  
  249.     if (c)  unGetMsgChar(c);    /* took one too many    */
  250.  
  251.     *dest = '\0';        /* tie off string    */
  252.  
  253.     return  c;
  254. }
  255.  
  256. /************************************************************************/
  257. /*    doActualWrite() to allow automatic bkp of msg file from RAM.    */
  258. /************************************************************************/
  259. doActualWrite(whichmsg, mFile, c)
  260. FILE *whichmsg;
  261. struct mBuf *mFile;
  262. unsigned c;
  263. {
  264.     ulong temp;
  265.     int toReturn = 0;
  266.  
  267.     if (mFile->sectBuf[mFile->thisChar] == 0xFF)  {
  268.     /* obliterating a msg    */
  269.     toReturn = 1;
  270.     }
  271.  
  272.     mFile->sectBuf[mFile->thisChar]   = c;
  273.  
  274.     mFile->thisChar    = ++mFile->thisChar % SECTSIZE;
  275.  
  276.     if (mFile->thisChar == 0) { /* time to write sector out and get next: */
  277.     temp = mFile->thisSector;
  278.     temp *= SECTSIZE;
  279.     fseek(whichmsg, temp, 0);
  280.     crypte(mFile->sectBuf, SECTSIZE, 0);
  281.     if (fwrite(mFile->sectBuf, SECTSIZE, 1, whichmsg) != 1) {
  282.         exitValue = CRASH_EXIT;
  283.         crashout("?putMsgChar-write fail");
  284.     }
  285.  
  286.     mFile->thisSector = ++mFile->thisSector % cfg.maxMSector;
  287.     temp = mFile->thisSector;
  288.     temp *= SECTSIZE;
  289.     fseek(whichmsg, temp, 0);
  290.     if (fread(mFile->sectBuf, SECTSIZE, 1, whichmsg) != 1) {
  291.         exitValue = CRASH_EXIT;
  292.         crashout("?putMsgChar-read fail");
  293.     }
  294.     crypte(mFile->sectBuf, SECTSIZE, 0);
  295.     }
  296.     return  toReturn;
  297. }
  298.  
  299. /************************************************************************/
  300. /*    doFlush() do actual writeup for specified msg file        */
  301. /************************************************************************/
  302. doFlush(whichmsg, mFile)
  303. FILE *whichmsg;
  304. struct mBuf *mFile;
  305. {
  306.     long int s;
  307.  
  308.     s = mFile->thisSector;
  309.     s *= SECTSIZE;
  310.     fseek(whichmsg, s, 0);
  311.     crypte(mFile->sectBuf, SECTSIZE, 0);
  312.     if (fwrite(mFile->sectBuf, SECTSIZE, 1, whichmsg) != 1) {
  313.     exitValue = CRASH_EXIT;
  314.     crashout("?ctdlmsg.sys write fail");
  315.     }
  316.     crypte(mFile->sectBuf, SECTSIZE, 0);
  317. }
  318.  
  319.  
  320. /************************************************************************/
  321. /*    dPree() Special utility for dPrintf() and mWCprintf        */
  322. /************************************************************************/
  323. dPree(func, start, length)
  324. int func;
  325. char *start;
  326. unsigned length;
  327. {
  328.     int (*fn)(), putMsgChar(), sendWCChar();
  329.  
  330.     switch (func) {
  331.     case 0:  fn = &putMsgChar; break;
  332.     case 1:  fn = &sendWCChar; break;
  333.     default: exitValue = CRASH_EXIT; crashout("dPree error value!");
  334.     }
  335.     while (length--)
  336.     if ((*fn)(*start++) == ERROR) return ERROR;
  337.  
  338. }
  339.  
  340. /************************************************************************/
  341. /*    dPrintf() write from format+args to disk            */
  342. /************************************************************************/
  343. dPrintf(format, args)
  344. unsigned      args;
  345. unsigned char *format;
  346. {
  347.     int  dPree();
  348.  
  349.     _fmtout(&dPree, 0, format, &args);
  350. }
  351.  
  352. /************************************************************************/
  353. /*    fakeFullCase() converts a message in uppercase-only to a    */
  354. /*    reasonable mix.  It can't possibly make matters worse...    */
  355. /*    Algorithm: First alphabetic after a period is uppercase, all    */
  356. /*    others are lowercase, excepting pronoun "I" is a special case.    */
  357. /*    We assume an imaginary period preceding the text.        */
  358. /************************************************************************/
  359. fakeFullCase(text)
  360. char *text;
  361. {
  362.     char toLower(), toUpper();
  363.     char *c;
  364.     char lastWasPeriod;
  365.     char state;
  366.  
  367.     for(lastWasPeriod=TRUE, c=text;   *c;  c++) {
  368.     if (
  369.         *c != '.'
  370.         &&
  371.         *c != '?'
  372.         &&
  373.         *c != '!'
  374.     ) {
  375.         if (isAlpha(*c)) {
  376.         if (lastWasPeriod)    *c    = toUpper(*c);
  377.         else            *c    = toLower(*c);
  378.         lastWasPeriod    = FALSE;
  379.         }
  380.     } else {
  381.         lastWasPeriod    = TRUE ;
  382.     }
  383.     }
  384.  
  385.     /* little state machine to search for ' i ': */
  386. #define NUTHIN        0
  387. #define FIRSTBLANK    1
  388. #define BLANKI        2
  389.     for (state=NUTHIN, c=text;    *c;  c++) {
  390.     switch (state) {
  391.     case NUTHIN:
  392.         if (isSpace(*c))    state    = FIRSTBLANK;
  393.         else        state    = NUTHIN    ;
  394.         break;
  395.     case FIRSTBLANK:
  396.         if (*c == 'i')    state    = BLANKI    ;
  397.         else        state    = NUTHIN    ;
  398.         break;
  399.     case BLANKI:
  400.         if (isSpace(*c))    state    = FIRSTBLANK;
  401.         else        state    = NUTHIN    ;
  402.  
  403.         if (!isAlpha(*c))    *(c-1)    = 'I';
  404.         break;
  405.     }
  406.     }
  407. }
  408.  
  409. /************************************************************************/
  410. /*    flushMsgBuf() wraps up writing a message to disk, takes into    */
  411. /*              account 2nd msg file if necessary         */
  412. /************************************************************************/
  413. flushMsgBuf()
  414. {
  415.     doFlush(msgfl, &mFile1);
  416.     if (cfg.mirror)
  417.     doFlush(msgfl2, &mFile2);
  418. }
  419.  
  420. /************************************************************************/
  421. /*    getMessage() reads a message off disk into RAM.         */
  422. /*    a previous call to setUp has specified the message.        */
  423. /************************************************************************/
  424. getMessage()
  425. {
  426.     unsigned char c;
  427.  
  428.     /* clear msgBuf out */
  429.     msgBuf.mbauth[ 0]    = '\0';
  430.     msgBuf.mbtime[ 0]    = '\0';
  431.     msgBuf.mbdate[ 0]    = '\0';
  432.     msgBuf.mborig[ 0]    = '\0';
  433.     msgBuf.mboname[0]    = '\0';
  434.     msgBuf.mbroom[ 0]    = '\0';
  435.     msgBuf.mbsrcId[0]    = '\0';
  436.     msgBuf.mbtext[ 0]    = '\0';
  437.     msgBuf.mbaddr[ 0]    = '\0';
  438.     msgBuf.mbto[   0]    = '\0';
  439.  
  440.     do c = getMsgChar(); while (c != 0xFF);    /* find start of msg    */
  441.  
  442.     msgBuf.mbheadChar    = mFile1.oldChar;     /* record location     */
  443.     msgBuf.mbheadSector = mFile1.oldSector;
  444.  
  445.     getMsgStr(msgBuf.mbId, NAMESIZE);
  446.  
  447.     do    {
  448.     c = getMsgChar();
  449.     switch (c) {
  450.     case 'A':    getMsgStr(msgBuf.mbauth,  NAMESIZE);    break;
  451.     case 'D':    getMsgStr(msgBuf.mbdate,  NAMESIZE);    break;
  452.     case 'C':    getMsgStr(msgBuf.mbtime,  NAMESIZE);    break;
  453.     case 'M':    /* just exit -- we'll read off disk */    break;
  454.     case 'N':    getMsgStr(msgBuf.mboname, NAMESIZE);    break;
  455.     case 'O':    getMsgStr(msgBuf.mborig,  NAMESIZE);    break;
  456.     case 'R':    getMsgStr(msgBuf.mbroom,  NAMESIZE);    break;
  457.     case 'S':    getMsgStr(msgBuf.mbsrcId, NAMESIZE);    break;
  458.     case 'T':    getMsgStr(msgBuf.mbto,      NAMESIZE);    break;
  459.     case 'Q':    getMsgStr(msgBuf.mbaddr,  NAMESIZE);    break;
  460.     default:
  461.         getMsgStr(msgBuf.mbtext, MAXTEXT);    /* discard unknown field  */
  462.         msgBuf.mbtext[0]    = '\0';
  463.         break;
  464.     }
  465.     } while (c != 'M'  &&  isAlpha(c));
  466. }
  467.  
  468. /************************************************************************/
  469. /*    getMsgChar() returns sequential chars from message on disk    */
  470. /************************************************************************/
  471. unsigned char getMsgChar()
  472. {
  473. #ifdef NEED_VISIBLE
  474.     char visible();
  475. #endif
  476.     long work;
  477.     char toReturn;
  478.  
  479.     if (GMCCache) {    /* someone did an unGetMsgChar() --return it    */
  480.     toReturn= GMCCache;
  481.     GMCCache= '\0';
  482.     return toReturn;
  483.     }
  484.  
  485.     mFile1.oldChar     = mFile1.thisChar;
  486.     mFile1.oldSector   = mFile1.thisSector;
  487.  
  488.     toReturn    = mFile1.sectBuf[mFile1.thisChar];
  489.  
  490.     mFile1.thisChar    = ++mFile1.thisChar % SECTSIZE;
  491.     if (mFile1.thisChar == 0) {
  492.     /* time to read next sector in: */
  493.     mFile1.thisSector  = ++mFile1.thisSector % cfg.maxMSector;
  494.     work = mFile1.thisSector;
  495.     work *= SECTSIZE;
  496.     fseek(msgfl, work, 0);
  497.     if (fread(mFile1.sectBuf, SECTSIZE, 1, msgfl) != 1) {
  498.         exitValue = CRASH_EXIT;
  499.         crashout("?nextMsgChar-read fail");
  500.     }
  501.     crypte(mFile1.sectBuf, SECTSIZE, 0);
  502.     }
  503.     return(toReturn);
  504. }
  505.  
  506. /************************************************************************/
  507. /*    getMsgStr() reads a string from message.buf            */
  508. /************************************************************************/
  509. getMsgStr(dest, lim)
  510. char *dest;
  511. int  lim;
  512. {
  513.     char c;
  514.  
  515.     while (c = getMsgChar()) {        /* read the complete string    */
  516.     if (lim) {            /* if we have room then     */
  517.         lim--;
  518.         *dest++ = c;        /* copy char to buffer        */
  519.     }
  520.     }
  521.     *dest = '\0';            /* tie string off with null    */
  522. }
  523.  
  524. /************************************************************************/
  525. /*    getWord() fetches one word from current message         */
  526. /************************************************************************/
  527. int getWord(dest, source, offset, lim)
  528. char *dest, *source;
  529. int  lim, offset;
  530. {
  531.     int i, j;
  532.  
  533.     /* skip leading blanks if any */
  534.     for (i = 0;  source[offset+i] ==' ' && i < lim;  i++);
  535.  
  536.     /* step over word */
  537.     for (;
  538.  
  539.      source[offset+i]   != ' '    &&
  540.      i            <  lim    &&
  541.      source[offset+i]   != 0;
  542.  
  543.      i++
  544.     );
  545.  
  546.     /* pick up any trailing blanks */
  547.     for (;  source[offset+i]==' ' && i<lim;  i++);
  548.  
  549.     /* copy word over */
  550.     for (j = 0; j < i; j++)  dest[j] = source[offset+j];
  551.     dest[j] = 0;    /* null to tie off string */
  552.  
  553.     return(offset+i);
  554. }
  555.  
  556. /************************************************************************/
  557. /*    mAbort() returns TRUE if the user has aborted typeout        */
  558. /*    Globals modified:    outFlag                 */
  559. /************************************************************************/
  560. char mAbort()
  561. {
  562.     char c, toReturn, oldEcho;
  563.  
  564.     /* Check for abort/pause from user */
  565.     if (outFlag == IMPERVIOUS)
  566.     toReturn    = FALSE;
  567.     else if (!BBSCharReady()) {
  568.     if (haveCarrier && !gotCarrier())
  569.         modIn();        /* Let modIn() report the problem    */
  570.     toReturn    = FALSE;
  571.     } else {
  572.     oldEcho  = echo;
  573.     echo     = NEITHER;
  574.     echoChar = 0;
  575.     c = toUpper(iChar());
  576.     switch (c) {
  577.     case XOFF:
  578.     case 'P':                    /*    pause:          */
  579.         c = iChar();                /* wait to resume */
  580.         if (
  581.         toLower(c) == 'd'
  582.         &&
  583.         aide
  584.         ) pullMessage = TRUE;
  585.         toReturn      = FALSE;
  586.         break;
  587.     case 'J':                    /* jump paragraph:*/
  588.         outFlag    = OUTPARAGRAPH;
  589.         toReturn    = FALSE;
  590.         break;
  591.     case 'N':                    /* next:          */
  592.         outFlag    = OUTNEXT;
  593.         toReturn    = TRUE;
  594.         break;
  595.     case 'S':                    /* skip:          */
  596.         outFlag    = OUTSKIP;
  597.         toReturn    = TRUE;
  598.         break;
  599.     default:
  600.         toReturn    = FALSE;
  601.         break;
  602.     }
  603.     echo    = oldEcho;
  604.     }
  605.     return toReturn;
  606. }
  607.  
  608. /************************************************************************/
  609. /*    makeMessage is menu-level routine to enter a message        */
  610. /*    Return: TRUE if message saved else FALSE            */
  611. /************************************************************************/
  612. makeMessage(uploading, name_Auth, mode, netMess)
  613. char *name_Auth;    /* name of recipient unless name_Auth == 0    */
  614. char uploading;     /* TRUE if message is coming via WC protocol    */
  615. char mode;        /* Is message being continued?            */
  616. char netMess;
  617. {
  618.     char         allUpper, *pc, toReturn;
  619.     struct logBuffer lBuf;
  620.     int          logNo;
  621.  
  622.     toReturn = FALSE;
  623.     if (mode) {
  624.     if (!heldMessage) {
  625.         mPrintf(" \n No message in the Held buffer!\007\n ");
  626.         return FALSE;
  627.     }
  628.         heldMessage = FALSE;
  629.     strTran(msgBuf.mbtext, tempMess.mbtext);
  630.     if (thisRoom == MAILROOM)
  631.         strTran(msgBuf.mbto, tempMess.mbto);
  632.     strTran(msgBuf.mbaddr, tempMess.mbaddr);
  633.     }
  634.     else {
  635.     msgBuf.mbto[0] = 0;
  636.     }
  637.  
  638.     logNo    = ERROR;/* not needed, but it's nice to initialize...    */
  639.  
  640.     if (thisRoom != MAILROOM && !loggedIn && !cfg.unlogEnterOk) {
  641.     mPrintf("Must log in to enter messages except MAIL to the SYSOP\n ");
  642.     return FALSE;
  643.     }
  644.  
  645.     if (thisRoom != MAILROOM)  msgBuf.mbto[0] = FALSE;
  646.     else {
  647.     if (!loggedIn || (!aide && cfg.noMail)) {
  648.         strCpy(msgBuf.mbto, "Sysop");
  649.         mPrintf(" (private mail to 'sysop')\n ");
  650.     } else {
  651.         if (name_Auth == NULL && msgBuf.mbto[0] == 0) {
  652.         getNormStr("recipient", msgBuf.mbto, NAMESIZE, ECHO);
  653.         if (strLen(msgBuf.mbto) == 0) return FALSE;
  654.         }
  655.         else if (name_Auth != NULL)
  656.         strCpy(msgBuf.mbto, name_Auth);
  657.  
  658.         if (!netMess && !msgBuf.mbaddr[0]) {
  659.         logNo    = findPerson(msgBuf.mbto, &lBuf);
  660.         if ((logNo == ERROR &&
  661.               (strCmpU(msgBuf.mbto, "Citadel") != SAMESTRING ||
  662.                !aide    ||      !onConsole) &&
  663.              hash(msgBuf.mbto) != hash("Sysop")) ||
  664.              strlen(msgBuf.mbto) == 0) {
  665.             mPrintf("No '%s' known", msgBuf.mbto);
  666.             return FALSE;
  667.         }
  668.         if (hash(msgBuf.mbto) != hash("Sysop") &&
  669.             strCmpU(msgBuf.mbto, "Citadel") != SAMESTRING)
  670.             strCpy(msgBuf.mbto, lBuf.lbname);  /* Get "true" rep.  */
  671.         if (strCmp(msgBuf.mbto, logBuf.lbname) == SAMESTRING) {
  672.             mPrintf("Can't send mail to yourself, silly!");
  673.             return FALSE;
  674.         }
  675.         }
  676.     }
  677.     }
  678.  
  679.  
  680.     strCpy(msgBuf.mbauth, logBuf.lbname);        /* record author*/
  681.     if (uploading ||
  682.     getText("message", msgBuf.mbto, mode) == TRUE) {
  683.     if (!uploading)   {
  684.         for (pc=msgBuf.mbtext, allUpper=TRUE;   *pc && allUpper;  pc++) {
  685.         if (toUpper(*pc) != *pc)   allUpper = FALSE;
  686.         }
  687.         if (allUpper)   fakeFullCase(msgBuf.mbtext, MAXTEXT);
  688.     }
  689.  
  690.     if (toReturn=putMessage(uploading)) noteMessage(&lBuf, logNo);
  691.     }
  692.     return toReturn;
  693. }
  694.  
  695. /************************************************************************/
  696. /*    mFormat() formats a string to modem and console         */
  697. /************************************************************************/
  698. mFormat(string)
  699. char *string;
  700. #define MAXWORD 256    /* maximum length of a word */
  701. {
  702.     char wordBuf[MAXWORD];
  703.     char mAbort();
  704.     int  i;
  705.  
  706.     for (i = 0;  string[i] && (outFlag == OUTOK      ||
  707.                  outFlag == IMPERVIOUS ||
  708.                  outFlag == OUTPARAGRAPH);    ) {
  709.     i = getWord(wordBuf, string, i, MAXWORD);
  710.     putWord(wordBuf);
  711.     if (mAbort()) return;
  712.     }
  713. }
  714.  
  715. /************************************************************************/
  716. /*    moveMessage() Moves a message for pullIt()            */
  717. /************************************************************************/
  718. moveMessage(m)
  719. int m;
  720. {
  721.     label blah;
  722.     int   i, roomTarg, ourRoom;
  723.     char  prompt[55];
  724.  
  725.     mPrintf("ove message\n ");
  726.     sPrintf(prompt, "where (C/R = '%s'): ", oldTarget);
  727.     getString(prompt, blah, 20, FALSE, ECHO);
  728.     if (!onLine()) return FALSE;
  729.     if (strLen(blah) == 0)
  730.     strCpy(blah, oldTarget);
  731.     if ((roomTarg = roomExists(blah)) == ERROR) {
  732.     mPrintf("'%s' does not exist.", blah);
  733.     return FALSE;
  734.     }
  735.  
  736.     strCpy(oldTarget, roomTab[roomTarg].rtname);
  737.  
  738.     pulledMLoc = roomBuf.msg[m].rbmsgLoc;
  739.     pulledMId  = roomBuf.msg[m].rbmsgNo ;
  740.  
  741.     for (i = m;  i > 0;  i--) {
  742.     roomBuf.msg[i].rbmsgLoc      = roomBuf.msg[i - 1].rbmsgLoc;
  743.     roomBuf.msg[i].rbmsgNo         = roomBuf.msg[i - 1].rbmsgNo ;
  744.     }
  745.     roomBuf.msg[0].rbmsgNo   = 0l;    /* mark new slot at end as free */
  746.     roomBuf.msg[0].rbmsgLoc  = 0 ;    /* mark new slot at end as free */
  747.  
  748.     noteRoom();
  749.     putRoom(ourRoom = thisRoom);
  750.     getRoom(roomTarg);
  751.  
  752.     note2Message(pulledMId, pulledMLoc);
  753.     putRoom(thisRoom);
  754.     noteRoom();
  755.     getRoom(ourRoom);
  756.     sPrintf(
  757.     msgBuf.mbtext,
  758.     "Following message from %s moved from %s> to %s> by %s",
  759.     (msgBuf.mbauth[0]) ? msgBuf.mbauth : "<anonymous>",
  760.     roomBuf.rbname,
  761.     oldTarget,
  762.     logBuf.lbname
  763.     );
  764.     aideMessage( /* noteDeletedMessage == */ TRUE);
  765.     return TRUE;
  766. }
  767.  
  768. /************************************************************************/
  769. /*    mPeek() dumps a sector in message.buf.    sysop debugging tool    */
  770. /************************************************************************/
  771. mPeek()
  772. {
  773. #ifdef TEST_SYS
  774.     char visible();
  775.     char blup[50];
  776.     unsigned char peekBuf[SECTSIZE];
  777.     int  col, row;
  778.     ulong r, s;
  779.  
  780.     sPrintf(blup, " sector to dump (between 0 - %d): ", cfg.maxMSector);
  781.     s = getNumber(blup, 0, cfg.maxMSector-1);
  782.     r = s * SECTSIZE;
  783.     fseek(msgfl, r, 0);
  784.     fread(peekBuf, SECTSIZE, 1, msgfl);
  785.     crypte(peekBuf, SECTSIZE, 0);
  786.     for (row = 0;  row < 2;  row++) {
  787.     printf("\n ");
  788.     for (col = 0;  col < 64;  col++) {
  789.         printf("%c", visible(peekBuf[row*64 +col]));
  790.     }
  791.     }
  792. #else
  793.     printf("Disabled\n");
  794. #endif
  795. }
  796.  
  797. /************************************************************************/
  798. /*    mspr() -- special function for this edition so we can be    */
  799. /*          semi-intelligent in formatting.            */
  800. /************************************************************************/
  801. #ifndef _C86_BIG
  802. mspr(recip, start, length)
  803. char     **recip, *start;
  804. unsigned length;
  805. {
  806.     while (length-- != 0)
  807.         *(*recip)++ = *start++;
  808.     **recip = 0;
  809. }
  810. #else
  811. static mspr(recip, start, length)
  812. unsigned recip;
  813. unsigned char *start;
  814. unsigned length;
  815. {
  816.     movmem(start, *starr[recip],length);
  817.     *starr[recip] += length;
  818.     **starr[recip]= 0;
  819. }
  820. #endif
  821.  
  822. /************************************************************************/
  823. /*    mPrintf() formats format+args to modem and console        */
  824. /************************************************************************/
  825. #ifndef _C86_BIG
  826. mPrintf(format, args)
  827. unsigned char *format;
  828. unsigned      args;
  829. {
  830.     int  mspr();
  831.     char mAbort();
  832.     char string[MAXWORD], *s;
  833.  
  834.     /* Here's all the fun, these 2 lines.  Each C does it different */
  835.     s = string;
  836.     _fmtout(&mspr, &s, format, &args);        /* C86 internal */
  837.     /* Ain't compatibility fun? */
  838.  
  839.     mFormat(string);
  840. }
  841. #else
  842. mPrintf(format, args)
  843. unsigned char *format;
  844. unsigned      args;
  845. {
  846.     unsigned char string[MAXWORD], *s;
  847.     s = string;
  848.   starr[j]=&s;
  849.   if(j>4){
  850.     exitValue = SYSOP_EXIT;
  851.     crashout("Big Model mPrintf crash!");
  852.   }
  853.   _fmtout(&mspr,j++,format,&args);
  854.   --j;
  855.   mFormat(string);
  856. }
  857. #endif
  858.  
  859. /************************************************************************/
  860. /*    mWCprintf() formats format+args to sendWCChar()         */
  861. /************************************************************************/
  862. mWCprintf(format, args)
  863. char     *format;
  864. unsigned args;
  865. {
  866.     int  dPree();
  867.  
  868.     _fmtout(&dPree, 1, format, &args);          /* C86 internal */
  869.     sendWCChar(0);    /* Send NULL since it did before */
  870. }
  871.  
  872. /************************************************************************/
  873. /*    noteLogMessage() slots message into log record            */
  874. /************************************************************************/
  875. noteLogMessage(lBuf, logNo)
  876. struct logBuffer   *lBuf;
  877. int           logNo;
  878. {
  879.     int i;
  880.  
  881.     /* store into recipient's log record: */
  882.     /* slide message pointers down to make room for this one: */
  883.     for (i = 0;  i < MAILSLOTS - 1;  i++) {
  884.     lBuf->lbslot[i]   = lBuf->lbslot[i + 1];
  885.     lBuf->lbId[  i]   = lBuf->lbId[  i + 1];
  886.     }
  887.  
  888.     /* slot this message in:    */
  889.     lBuf->lbId[MAILSLOTS-1]      = cfg.newest;
  890.     lBuf->lbslot[MAILSLOTS-1]      = cfg.catSector;
  891.  
  892.     putLog(lBuf, logNo);
  893. }
  894.  
  895. /************************************************************************/
  896. /*    noteMessage() slots message into current room            */
  897. /************************************************************************/
  898. noteMessage(lBuf, logNo)
  899. struct logBuffer   *lBuf;
  900. int           logNo;
  901. {
  902.     struct logBuffer lBuf2;
  903.     int logRover;
  904.  
  905.     logBuf.lbvisit[0]    = ++cfg.newest;
  906.  
  907.     if (thisRoom != MAILROOM) {
  908.     note2Message(cfg.newest, cfg.catSector);
  909.  
  910.     /* write it to disk:        */
  911.     putRoom(thisRoom);
  912.     noteRoom();
  913.     } else {
  914.     if (strCmpU(msgBuf.mbto, "Sysop") == SAMESTRING)  {
  915.        if (!msgBuf.mbaddr[0]) {
  916.            getRoom(AIDEROOM);
  917.  
  918.            /* enter in Aide> room -- 'sysop' is special */
  919.            note2Message(cfg.newest, cfg.catSector);
  920.  
  921.            /* write it to disk:           */
  922.            putRoom(AIDEROOM);
  923.            noteRoom();
  924.  
  925.            getRoom(MAILROOM);
  926.         }
  927.         /* note in ourself if logged in: */
  928.         if (loggedIn) {
  929.         noteLogMessage(&logBuf, thisLog);
  930.         fillMailRoom();
  931.         }
  932.     } else if (strCmpU(msgBuf.mbto, "Citadel") == SAMESTRING &&
  933.            !msgBuf.mbaddr[0]) {
  934.         for (logRover = 0; logRover < cfg.MAXLOGTAB; logRover++) {
  935.         printf("Log %d\r", logRover);        /* Notify sysop    */
  936.         getLog(&lBuf2, logRover);
  937.         if (lBuf2.lbflags.L_INUSE) {
  938.             noteLogMessage(&lBuf2, logRover);
  939.         }
  940.         }
  941.         noteLogMessage(&logBuf, thisLog);        /* note in ourself    */
  942.         fillMailRoom();                /* update room also */
  943.     } else {
  944.         if (logNo != thisLog && !msgBuf.mbaddr[0])    {
  945.         noteLogMessage(lBuf, logNo);        /* note in recipient*/
  946.         }
  947.         if (loggedIn) {
  948.         noteLogMessage(&logBuf, thisLog);   /* note in ourself    */
  949.         fillMailRoom();             /* update room also */
  950.         }
  951.     }
  952.     }
  953.  
  954.     msgBuf.mbaddr[0] = 0;
  955.     msgBuf.mbto[0]   = 0;
  956.  
  957.     /* make message official:    */
  958.     cfg.catSector   = mFile1.thisSector;
  959.     cfg.catChar     = mFile1.thisChar;
  960.     setUp(FALSE);
  961. }
  962.  
  963. /************************************************************************/
  964. /*    note2Message() makes slot in current room... called by noteMess */
  965. /************************************************************************/
  966. note2Message(id, loc)
  967. ulong     id;
  968. unsigned loc;
  969. {
  970.     int i;
  971.  
  972.     /* store into current room: */
  973.     /* slide message pointers down to make room for this one:        */
  974.     for (i = 0;  i < MSGSPERRM - 1;  i++) {
  975.     roomBuf.msg[i].rbmsgLoc  = roomBuf.msg[i+1].rbmsgLoc;
  976.     roomBuf.msg[i].rbmsgNo     = roomBuf.msg[i+1].rbmsgNo ;
  977.     }
  978.  
  979.     /* slot this message in:        */
  980.     roomBuf.msg[MSGSPERRM-1].rbmsgNo     = id ;
  981.     roomBuf.msg[MSGSPERRM-1].rbmsgLoc     = loc;
  982. }
  983.  
  984. /************************************************************************/
  985. /*    printMessage() prints indicated message on modem & console    */
  986. /************************************************************************/
  987. printMessage(loc, id, name_Auth)
  988. char     *name_Auth; /* Author buffer if thisRoom == mailRoom */
  989. unsigned loc;         /* sector in message.buf         */
  990. ulong     id;         /* unique-for-some-time ID#     */
  991. {
  992.     char  dGetWord();
  993.     char  c, moreFollows;
  994.     ulong here;
  995.     long val, atoi();
  996.     int strip;
  997.  
  998.     startAt(msgfl, &mFile1, loc, 0);
  999.  
  1000.     do {
  1001.     getMessage();
  1002.     sscanf(msgBuf.mbId, "%ld", &here);
  1003.     } while (here != id &&  mFile1.thisSector == loc);
  1004.  
  1005.     if (here != id  &&    !usingWCprotocol) {
  1006.     mPrintf("?can't find message! Looking for %lu in sector %u!\n ",
  1007.             id, loc);
  1008.     if (debug)
  1009.         printf(" loc=%u, id=%lu, mbIds=%s, here=%lu\n",
  1010.         loc, id, msgBuf.mbId, here
  1011.         );
  1012.  
  1013.     return;
  1014.     }
  1015.  
  1016.     if (!usingWCprotocol) {
  1017.     doCR();
  1018.  
  1019.     if (msgBuf.mbdate[ 0])       mPrintf("   %s ", msgBuf.mbdate);
  1020.     if (msgBuf.mbtime[ 0] && sendTime) mPrintf("%s ", msgBuf.mbtime);
  1021.     if (msgBuf.mbauth[ 0]) {
  1022.         mPrintf(    "from %s",    msgBuf.mbauth );
  1023.         if (thisRoom == MAILROOM)
  1024.         strCpy(name_Auth, msgBuf.mbauth);
  1025.     }
  1026.     if (msgBuf.mboname[0])        mPrintf(    " @%s",       msgBuf.mboname);
  1027.     if (strCmpU(msgBuf.mbroom, roomBuf.rbname) != SAMESTRING) {
  1028.         mPrintf(" in %s>",      msgBuf.mbroom );
  1029.     }
  1030.     if (msgBuf.mbto[   0])        mPrintf(    " to %s",     msgBuf.mbto   );
  1031.     if (msgBuf.mbaddr[ 0])        mPrintf(    " (on %s)",   msgBuf.mbaddr );
  1032.  
  1033.     doCR();
  1034.  
  1035.     while (1) {
  1036.         moreFollows     = dGetWord(msgBuf.mbtext, 150);
  1037.         /* strip control Ls out of the output            */
  1038.         for (strip = 0; msgBuf.mbtext[strip] != 0; strip++)
  1039.         if (msgBuf.mbtext[strip] == 0x0c)
  1040.             msgBuf.mbtext[strip] = ' ';
  1041.         putWord(msgBuf.mbtext);
  1042.         if (!(moreFollows  &&  !mAbort())) {
  1043.         if (outFlag == OUTNEXT)     /* If <N>ext, extra line */
  1044.             doCR();
  1045.         break;
  1046.         }
  1047.     }
  1048.     doCR();
  1049.     }
  1050.     else {
  1051.     /* networking dump of message: */
  1052.  
  1053.     /* fill in local node in origin fields if local message: */
  1054.     if (!msgBuf.mborig[ 0])
  1055.         strCpy(msgBuf.mborig,  cfg.nodeId + cfg.codeBuf  );
  1056.     if (!msgBuf.mboname[0])
  1057.         strCpy(msgBuf.mboname, cfg.nodeName + cfg.codeBuf);
  1058.  
  1059.     /* Convert # to 8-bit Citadel style for compatibility    */
  1060.     if (!msgBuf.mbsrcId[0]) {
  1061.         val = atoi(msgBuf.mbId);
  1062.         sPrintf(msgBuf.mbsrcId, "%ld %ld",
  1063.               val & 0xFFFF0000l,val & 0xFFFFl);
  1064.     }
  1065.  
  1066.     /* send header fields out: */
  1067.     if (msgBuf.mbauth[ 0])    mWCprintf("A%s", msgBuf.mbauth );
  1068.     if (msgBuf.mbdate[ 0])    mWCprintf("D%s", msgBuf.mbdate );
  1069.     if (msgBuf.mbtime[ 0])    mWCprintf("C%s", msgBuf.mbtime );
  1070.     if (msgBuf.mboname[0])    mWCprintf("N%s", msgBuf.mboname);
  1071.     if (msgBuf.mborig[ 0])    mWCprintf("O%s", msgBuf.mborig );
  1072.     if (msgBuf.mbroom[ 0])    mWCprintf("R%s", msgBuf.mbroom );
  1073.     if (msgBuf.mbsrcId[0])    mWCprintf("S%s", msgBuf.mbsrcId);
  1074.     if (msgBuf.mbto[   0])    mWCprintf("T%s", msgBuf.mbto   );
  1075.  
  1076.     /* send message text proper: */
  1077.     sendWCChar('M');
  1078.     do  {
  1079.         c = getMsgChar();
  1080.         if (c=='\n')  c='\r';
  1081.         if (!sendWCChar(c)) break;
  1082.     } while (c);
  1083.     }
  1084.     msgBuf.mbaddr[0] = 0;
  1085. }
  1086.  
  1087. /************************************************************************/
  1088. /*    pullIt() is a sysop special to remove a message from a room    */
  1089. /************************************************************************/
  1090. pullIt(m)
  1091. int m;
  1092. {
  1093.     char  finished;
  1094.     label blah;
  1095.     char  answer;
  1096.  
  1097.     /* confirm that we're removing the right one:    */
  1098.     outFlag = OUTOK;
  1099.     printMessage(roomBuf.msg[m].rbmsgLoc, roomBuf.msg[m].rbmsgNo, blah);
  1100.  
  1101.     for (finished = FALSE; !finished;)    {
  1102.     do {
  1103.         outFlag = IMPERVIOUS;
  1104.         mPrintf("\n <D>elete <M>ove <A>bort? (D/M/A) ");
  1105.         answer = toUpper(iChar());
  1106.         if (answer == 'A' ||
  1107.         answer == 'D' ||
  1108.         answer == 'M')
  1109.         break;
  1110.     } while (onLine());
  1111.  
  1112.     outFlag = OUTOK;
  1113.     if (answer == 'A' || !onLine()) return FALSE;
  1114.  
  1115.     if (answer == 'D')    finished = deleteMessage(m);
  1116.     else if (answer == 'M') finished = moveMessage(m);
  1117.     }
  1118.     return TRUE;
  1119. }
  1120.  
  1121. /************************************************************************/
  1122. /*    putLong() puts a long integer to file fd            */
  1123. /************************************************************************/
  1124. putLong(fd, nm)
  1125. FILE *fd;
  1126. ulong nm;
  1127. {
  1128.     unsigned char c;
  1129.  
  1130.     c = (unsigned char) ((nm & 0xFF000000) >> 24);
  1131.     if (fputc(c, fd) == EOF) {
  1132.     exitValue = CRASH_EXIT;
  1133.     crashout("putLong error!");
  1134.     }
  1135.     c = (unsigned char) ((nm & 0x00FF0000) >> 16);
  1136.     if (fputc(c, fd) == EOF) {
  1137.     exitValue = CRASH_EXIT;
  1138.     crashout("putLong error!");
  1139.     }
  1140.     c = (unsigned char) ((nm & 0x0000FF00) >>  8);
  1141.     if (fputc(c, fd) == EOF) {
  1142.     exitValue = CRASH_EXIT;
  1143.     crashout("putLong error!");
  1144.     }
  1145.     c = (unsigned char) (nm & 0x000000FF);
  1146.     if (fputc(c, fd) == EOF) {
  1147.     exitValue = CRASH_EXIT;
  1148.     crashout("putLong error!");
  1149.     }
  1150. }
  1151.  
  1152. /************************************************************************/
  1153. /*    putMessage() stores a message to disk                */
  1154. /*    Always called before noteMessage() -- newest not ++ed yet.    */
  1155. /*    Returns: TRUE on successful save, else FALSE            */
  1156. /************************************************************************/
  1157. char putMessage(uploading)
  1158. char uploading;     /* true to get text via WC modem input, not RAM */
  1159. {
  1160.     char  *s, allOk, *month, *ml;
  1161.     label fn, ourCode, theirCode;
  1162.     int   putWCChar();
  1163.     int   year, day, h, m, netPlace;
  1164.     FILE  *fopen(), *fd;
  1165.  
  1166.     startAt(msgfl, &mFile1, cfg.catSector, cfg.catChar);
  1167.                     /* tell putMsgChar where to write    */
  1168.     if (cfg.mirror)
  1169.     startAt(msgfl2, &mFile2, cfg.catSector, cfg.catChar);
  1170.  
  1171.     putMsgChar(0xFF);            /* start-of-message         */
  1172.  
  1173.     /* write message ID */
  1174.     dPrintf("%lu", cfg.newest + 1);
  1175.     putMsgChar(0);
  1176.  
  1177.     /* write date:    */
  1178.     getdate(&year, &month, &day, &h, &m);
  1179.     dPrintf("D%d%s%02d", year, month, day);
  1180.     putMsgChar(0);
  1181.  
  1182.     /* write time:    */
  1183.     if (h >= 12)
  1184.     ml = "pm";
  1185.     else
  1186.     ml = "am";
  1187.     if (h >= 13)
  1188.     h -= 12;
  1189.     if (h == 0)
  1190.     h = 12;
  1191.     dPrintf("C%d:%02d %s", h, m, ml);
  1192.     putMsgChar(0);
  1193.  
  1194.     /* write room name out:        */
  1195.     dPrintf("R%s", roomBuf.rbname);
  1196.     putMsgChar(0);
  1197.  
  1198.     if (loggedIn || strCmpU(msgBuf.mbauth, "Citadel") == SAMESTRING) {
  1199.     /* write author's name out:        */
  1200.     dPrintf("A%s", msgBuf.mbauth);
  1201.     putMsgChar(0);        /* null to end string   */
  1202.     }
  1203.  
  1204.     if (msgBuf.mbto[0]) {    /* private message -- write addressee    */
  1205.     dPrintf("T%s", msgBuf.mbto);
  1206.     putMsgChar(0);
  1207.     }
  1208.  
  1209.     if (msgBuf.mbaddr[0]) {    /* net message routing -- put to temp    */
  1210.     netPlace = searchNameNet(msgBuf.mbaddr);
  1211.     getNet(netPlace);
  1212.     sPrintf(fn, "a:%d.ml", thisNet);
  1213.     fn[0] += cfg.netDisk;
  1214.     if ((fd = fopen(fn, "ab")) == NULL) {
  1215.         exitValue = CRASH_EXIT;
  1216.         crashout("putMessage -- couldn't open mail router!");
  1217.     }
  1218.     putLong(fd, cfg.newest + 1);
  1219.     fputc(((cfg.catSector & 0xff00) >> 8), fd);
  1220.     fputc(((cfg.catSector & 0xff)), fd);
  1221.     fclose(fd);
  1222.     getArea(cfg.codeBuf + cfg.nodeId, ourCode  );
  1223.     getArea(netBuf.netId        , theirCode);
  1224.     if (strCmpU(theirCode, ourCode) != SAMESTRING) {
  1225.         if (logBuf.credit == 0) {
  1226.         exitValue = CRASH_EXIT;
  1227.         crashout("Someone obtained illegal l-d networking privs!");
  1228.         }
  1229.         logBuf.credit--;
  1230.         storeLog();
  1231.     }
  1232.     netBuf.nbflags.normal_mail = TRUE;
  1233.     putNet(netPlace);
  1234.     dPrintf("Q%s", netBuf.netName);
  1235.     putMsgChar(0);
  1236.     }
  1237.  
  1238.     /* write message text by hand because it would overrun dPrintf buffer: */
  1239.     putMsgChar('M');    /* M-for-message.    */
  1240.     if (!uploading) {
  1241.     for (s = msgBuf.mbtext;  *s;  s++) putMsgChar(*s);
  1242.     allOk    = TRUE;
  1243.     } else {
  1244.     outFlag = FALSE;    /* setup for putWCChar()    */
  1245.     allOk    = readFile(putWCChar);
  1246.     }
  1247.  
  1248.     if (allOk) {
  1249.     putMsgChar(0);        /* null to end text     */
  1250.  
  1251.     flushMsgBuf();
  1252.     } else {
  1253.     flushMsgBuf();        /* so message count is ok    */
  1254.  
  1255.     /* erase start-of-message indicator: */
  1256.     startAt(msgfl, &mFile1, cfg.catSector, cfg.catChar);
  1257.     if (cfg.mirror)
  1258.         startAt(msgfl2, &mFile2, cfg.catSector, cfg.catChar);
  1259.     putMsgChar(0);        /* overwrite 0xFF byte    */
  1260.     }
  1261.  
  1262.     return  allOk;
  1263. }
  1264.  
  1265. /************************************************************************/
  1266. /*    putMsgChar() writes successive message chars to disk        */
  1267. /*    Globals:    thisChar=    thisSector=            */
  1268. /*    Returns:    ERROR if problems else TRUE            */
  1269. /************************************************************************/
  1270. int putMsgChar(c)
  1271. unsigned char c;
  1272. {
  1273.     int  toReturn;
  1274.     int  count1, count2;
  1275.     long temp;
  1276.  
  1277.     toReturn = TRUE;
  1278.     count1 = doActualWrite(msgfl, &mFile1, c);
  1279.     if (cfg.mirror) {
  1280.     count2 = doActualWrite(msgfl2, &mFile2, c);
  1281.     if (count1 != count2) printf("Mirror msg count discrepancy!");
  1282.     }
  1283.     if (count1)
  1284.     logBuf.lbvisit[(MAXVISIT-1)]    = ++cfg.oldest;
  1285.     return toReturn;
  1286. }
  1287.  
  1288. /************************************************************************/
  1289. /*    putNetMessage() stores a message to disk            */
  1290. /*    Always called before noteMessage() -- newestLo not ++ed yet.    */
  1291. /*    Returns: TRUE on successful save, else FALSE.            */
  1292. /************************************************************************/
  1293. putNetMessage()
  1294. {
  1295.     char *s, allOk;
  1296.  
  1297.     startAt(msgfl, &mFile1, cfg.catSector, cfg.catChar);
  1298.                     /* tell putMsgChar where to write    */
  1299.     if (cfg.mirror)
  1300.     startAt(msgfl2, &mFile2, cfg.catSector, cfg.catChar);
  1301.  
  1302.     putMsgChar(0xFF);            /* start-of-message         */
  1303.  
  1304.     /* write message ID */
  1305.     dPrintf("%lu", cfg.newest + 1);
  1306.     putMsgChar(0);
  1307.  
  1308.     /* write date:    */
  1309.     dPrintf("D%s", tempMess.mbdate);
  1310.     putMsgChar(0);
  1311.  
  1312.     /* write room name out:        */
  1313.     dPrintf("R%s", roomBuf.rbname);
  1314.     putMsgChar(0);
  1315.  
  1316.     /* write source node name out:    */
  1317.     dPrintf("N%s", tempMess.mboname);
  1318.     putMsgChar(0);
  1319.  
  1320.     /* write source node id out:    */
  1321.     dPrintf("O%s", tempMess.mborig);
  1322.     putMsgChar(0);
  1323.  
  1324.     /* write source id out:        */
  1325.     dPrintf("S%s", tempMess.mbsrcId);
  1326.     putMsgChar(0);
  1327.  
  1328.     if (tempMess.mbauth[0]) {
  1329.     /* write author's name out:        */
  1330.     dPrintf("A%s", tempMess.mbauth);
  1331.     putMsgChar(0);        /* null to end string   */
  1332.     }
  1333.  
  1334.     if (tempMess.mbto[0]) {      /* private message -- write addressee   */
  1335.     dPrintf("T%s", tempMess.mbto);
  1336.     putMsgChar(0);
  1337.     }
  1338.  
  1339.     if (tempMess.mbtime[0]) {
  1340.     dPrintf("C%s", tempMess.mbtime);
  1341.     putMsgChar(0);
  1342.     }
  1343.  
  1344.     /* write message text by hand because it would overrun dPrintf buffer: */
  1345.     putMsgChar('M');    /* M-for-message.    */
  1346.     for (s=tempMess.mbtext;  *s;  s++) putMsgChar(*s);
  1347.  
  1348.     putMsgChar(0);    /* null to end text        */
  1349.     flushMsgBuf();
  1350. }
  1351.  
  1352. /************************************************************************/
  1353. /*    putWord() writes one word to modem & console            */
  1354. /************************************************************************/
  1355. putWord(st)
  1356. char *st;
  1357. {
  1358.     char *s;
  1359.     int  newColumn;
  1360.  
  1361.     for (newColumn = crtColumn, s = st;  *s; s++)   {
  1362.     if (*s != TAB)    ++newColumn;
  1363.     else        while (++newColumn % 8);
  1364.     }
  1365.     if (newColumn > termWidth)     doCR();
  1366.  
  1367.     for (;  *st;  st++) {
  1368.  
  1369.     if (*st != TAB) ++crtColumn;
  1370.     else        while (++crtColumn % 8);
  1371.  
  1372.     /* worry about words longer than a line:    */
  1373.     if (crtColumn > termWidth) doCR();
  1374.  
  1375.     if (prevChar!=NEWLINE  ||  (*st > ' '))   oChar(*st);
  1376.     else {
  1377.         /* end of paragraph: */
  1378.         if (outFlag == OUTPARAGRAPH)   {
  1379.         outFlag = OUTOK;
  1380.         }
  1381.         doCR();
  1382.         oChar(*st);
  1383.     }
  1384.     }
  1385. }
  1386.  
  1387. /************************************************************************/
  1388. /*    showMessages() is routine to print roomful of msgs        */
  1389. /************************************************************************/
  1390. showMessages(whichMess, revOrder)
  1391. char whichMess, revOrder;
  1392. {
  1393.     char  name_Auth[NAMESIZE];
  1394.     int   i;
  1395.     int   start, finish, increment;
  1396.     ulong lowLim, highLim, msgNo;
  1397.     char  pulled;
  1398.  
  1399.     setUp(FALSE);
  1400.  
  1401.     if (thisRoom == MAILROOM && !loggedIn) {
  1402.     tutorial("POLICY.HLP");
  1403.     return ;
  1404.     }
  1405.  
  1406.     if (!expert && !usingWCprotocol)
  1407.         mPrintf("\n <J>ump <N>ext <P>ause <S>top");
  1408.  
  1409.     if (whichIO != CONSOLE && thisRoom == MAILROOM) echo = CALLER;
  1410.  
  1411.     /* Allow for reverse retrieval: */
  1412.     if (!revOrder) {
  1413.     start        = 0;
  1414.     finish        = MSGSPERRM;
  1415.     increment   = 1;
  1416.     } else {
  1417.     start        = (MSGSPERRM -1);
  1418.     finish        = -1;
  1419.     increment   = -1;
  1420.     }
  1421.  
  1422.     switch (whichMess)     {
  1423.     case NEWoNLY:
  1424.     lowLim    = logBuf.lbvisit[ logBuf.lbgen[thisRoom] & CALLMASK]+1;
  1425.     highLim = cfg.newest;
  1426.         if (!revOrder && !usingWCprotocol && thisRoom != MAILROOM && oldToo) {
  1427.             for (i = MSGSPERRM - 1; i != -1; i--)
  1428.                 if (lowLim > roomBuf.msg[i].rbmsgNo &&
  1429.                     roomBuf.msg[i].rbmsgNo >= cfg.oldest)
  1430.                     break;
  1431.             if (i != -1)
  1432.                 printMessage(roomBuf.msg[i].rbmsgLoc, roomBuf.msg[i].rbmsgNo,
  1433.                              name_Auth);
  1434.         }
  1435.     break;
  1436.     case OLDaNDnEW:
  1437.     lowLim    = cfg.oldest;
  1438.     highLim = cfg.newest;
  1439.     break;
  1440.     case OLDoNLY:
  1441.     lowLim    = cfg.oldest;
  1442.     highLim = logBuf.lbvisit[ logBuf.lbgen[thisRoom] & CALLMASK];
  1443.     break;
  1444.     }
  1445.  
  1446.     /* stuff may have scrolled off system unseen, so: */
  1447.     if (cfg.oldest  > lowLim) {
  1448.     lowLim = cfg.oldest;
  1449.     }
  1450.  
  1451.     for (i = start; i != finish && onLine(); i += increment) {
  1452.     if (outFlag != OUTOK) {
  1453.         if (outFlag == OUTNEXT || outFlag == OUTPARAGRAPH)
  1454.         outFlag = OUTOK;
  1455.         else if (outFlag == OUTSKIP)   {
  1456.         echo = BOTH;
  1457.         return;
  1458.         }
  1459.     }
  1460.  
  1461.     msgNo    = roomBuf.msg[i].rbmsgNo;
  1462.     if (
  1463.         msgNo >= lowLim
  1464.         &&
  1465.         highLim >= msgNo
  1466.      ) {
  1467.         printMessage(roomBuf.msg[i].rbmsgLoc, msgNo, name_Auth);
  1468.  
  1469.         /*    Pull current message from room if flag set */
  1470.         if (pullMessage) {
  1471.         pullMessage = FALSE;
  1472.         pulled = pullIt(i);
  1473.         outFlag = OUTOK;
  1474.         if (revOrder && pulled)   i++;
  1475.         }
  1476.         else
  1477.         pulled = FALSE;
  1478.  
  1479.         if (
  1480.         !usingWCprotocol
  1481.         &&
  1482.         !pulled
  1483.         &&
  1484.         strCmpU(name_Auth, logBuf.lbname) != SAMESTRING
  1485.         &&
  1486.         thisRoom  == MAILROOM
  1487.         &&
  1488.         whichMess == NEWoNLY
  1489.         &&
  1490.         msgBuf.mborig[0] == 0    /* i.e. is local mail        */
  1491.         &&
  1492.         getYesNo("respond")
  1493.         ) {
  1494.         if (makeMessage( /* uploading== */ FALSE, name_Auth, 0,FALSE))
  1495.             i--;
  1496.         if (whichIO != CONSOLE && thisRoom == MAILROOM)
  1497.             echo = CALLER;    /* Restore privacy zapped by make... */
  1498.         outFlag = OUTOK;
  1499.         }
  1500.     }
  1501.     }
  1502.     echo = BOTH;
  1503. }
  1504.  
  1505. /************************************************************************/
  1506. /*    startAt() sets location to begin reading message from        */
  1507. /************************************************************************/
  1508. startAt(whichmsg, mFile, sect, byt)
  1509. unsigned sect;
  1510. int     byt;
  1511. FILE     *whichmsg;
  1512. struct mBuf *mFile;
  1513. {
  1514.     long temp;
  1515.  
  1516.     GMCCache  = '\0';    /* cache to unGetMsgChar() into */
  1517.  
  1518.     if (sect >= cfg.maxMSector) {
  1519.     printf("?startAt s=%u,b=%d", sect, byt);
  1520.     exitValue = CRASH_EXIT;
  1521.     crashout("?startAt crash");
  1522.     }
  1523.     mFile->thisChar    = byt;
  1524.     mFile->thisSector  = sect;
  1525.  
  1526.     temp = sect;
  1527.     temp *= SECTSIZE;
  1528.     fseek(whichmsg, temp, 0);
  1529.     if (fread(mFile->sectBuf, SECTSIZE, 1, whichmsg) != 1) {
  1530.     exitValue = CRASH_EXIT;
  1531.     crashout("?startAt read fail");
  1532.     }
  1533.     crypte(mFile->sectBuf, SECTSIZE, 0);
  1534. }
  1535.  
  1536. /************************************************************************/
  1537. /*    unGetMsgChar() returns (at most one) char to getMsgChar()    */
  1538. /************************************************************************/
  1539. unGetMsgChar(c)
  1540. unsigned char c;
  1541. {
  1542.     GMCCache    = c;
  1543. }
  1544.  
  1545. /************************************************************************/
  1546. /*    exportSector() returns current sector to write to        */
  1547. /************************************************************************/
  1548. unsigned exportSector()
  1549. {
  1550.     return mFile1.thisSector;
  1551. }
  1552.